package com.example.baselibrary.utlis;

import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import android.util.LruCache;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.RandomAccessFile;
import java.io.Serializable;
import java.lang.ref.WeakReference;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.util.zip.InflaterInputStream;

/**
 * 完整实现的优化缓存工具类
 * 功能特点：
 * 1. 内存+磁盘双缓存
 * 2. 自动资源回收
 * 3. 延迟写入机制
 * 4. 严格单例管理
 * 5. 支持多种数据类型
 */
public final class CompleteACache implements Closeable {
    private static final String TAG = "CompleteACache";
    private static final int DEFAULT_MAX_MEMORY_SIZE = 10 * 1024 * 1024; // 10MB
    private static final int DEFAULT_MAX_DISK_SIZE = 100 * 1024 * 1024; // 100MB
    private static final int DEFAULT_MAX_COUNT = 1000;
    private static final int WRITE_DELAY_MS = 500;
    private static final int COMPRESS_THRESHOLD = 1024; // 1KB

    // 单例管理
    private static final Map<String, WeakReference<CompleteACache>> instanceMap = new ConcurrentHashMap<>();
    private static final ExecutorService ioExecutor = Executors.newFixedThreadPool(4);
    private static final ScheduledExecutorService scheduledExecutor =
            Executors.newSingleThreadScheduledExecutor();

    // 核心组件
    private final LruCache<String, CacheItem> memoryCache;
    private final Map<String, WeakReference<CacheItem>> weakCache = new ConcurrentHashMap<>();
    private final DiskCacheManager diskCache;
    private final PendingWriteManager pendingWrites;
    private final Config config;
    private final File storageDir;
    private final String instanceKey;
    private final Context appContext;

    public static final class Config {
        public boolean enablePersistence = true;
        public boolean humanReadable = false;
        public boolean compressLargeData = true;
        public int maxMemorySize = DEFAULT_MAX_MEMORY_SIZE;
        public int maxDiskSize = DEFAULT_MAX_DISK_SIZE;
        public int maxCount = DEFAULT_MAX_COUNT;
        public int writeDelay = WRITE_DELAY_MS;

        public Config() {}

        public Config setMaxMemorySize(int maxMemorySize) {
            this.maxMemorySize = maxMemorySize;
            return this;
        }

        public Config setMaxDiskSize(int maxDiskSize) {
            this.maxDiskSize = maxDiskSize;
            return this;
        }

        public Config setMaxCount(int maxCount) {
            this.maxCount = maxCount;
            return this;
        }

        public Config setWriteDelay(int writeDelayMs) {
            this.writeDelay = writeDelayMs;
            return this;
        }

        public Config setEnablePersistence(boolean enable) {
            this.enablePersistence = enable;
            return this;
        }

        public Config setHumanReadable(boolean readable) {
            this.humanReadable = readable;
            return this;
        }

        public Config setCompressLargeData(boolean compress) {
            this.compressLargeData = compress;
            return this;
        }
    }

    private static final class CacheItem implements Closeable {
        final Object data;
        final long timestamp;
        final int saveTime;
        volatile boolean dirty;
        final String type;

        CacheItem(Object data, int saveTime, String type) {
            this.data = data;
            this.saveTime = saveTime;
            this.timestamp = System.currentTimeMillis();
            this.dirty = true;
            this.type = type;
        }

        boolean isDue() {
            return saveTime > 0 && (System.currentTimeMillis() > timestamp + saveTime * 1000L);
        }

        @Override
        public void close() {
            if (data instanceof Closeable) {
                try {
                    ((Closeable) data).close();
                } catch (IOException e) {
                    Log.w(TAG, "Close cache item failed", e);
                }
            } else if (data instanceof Bitmap) {
                ((Bitmap) data).recycle();
            }
        }
    }

    public static final class Builder {
        private final Context context;
        private Config config = new Config();
        private String cacheName = "CompleteCache";
        private File customCacheDir;
        private File storageDir;

        public Builder(Context context) {
            this.context = context.getApplicationContext();
        }

        public Builder setConfig(Config config) {
            this.config = config;
            return this;
        }

        public Builder setCacheName(String cacheName) {
            this.cacheName = cacheName;
            return this;
        }

        public CompleteACache build() {
            File cacheDir = customCacheDir != null ? customCacheDir :
                    new File(context.getCacheDir(), cacheName);
            File storage = storageDir != null ? storageDir :
                    new File(context.getFilesDir(), cacheName + "_Storage");

            return getInstance(context, cacheDir, storage, config);
        }
    }

    private CompleteACache(Context context, File cacheDir, File storageDir, Config config, String instanceKey) {
        this.appContext = context.getApplicationContext();
        this.config = config;
        this.storageDir = storageDir;
        this.instanceKey = instanceKey;

        this.memoryCache = new LruCache<String, CacheItem>(config.maxMemorySize) {
            @Override
            protected int sizeOf(String key, CacheItem item) {
                return calculateItemSize(item);
            }

            @Override
            protected void entryRemoved(boolean evicted, String key,
                                        CacheItem oldValue, CacheItem newValue) {
                if (oldValue != null) {
                    if (evicted && oldValue.dirty) {
                        scheduleWrite(key, oldValue);
                    }
                    weakCache.put(key, new WeakReference<>(oldValue));
                }
            }
        };

        this.diskCache = new DiskCacheManager(cacheDir, storageDir, config);
        this.pendingWrites = new PendingWriteManager();

        warmUpCache();
        registerMemoryWatcher();
    }

    public static CompleteACache getInstance(Context context, File cacheDir, File storageDir, Config config) {
        Context appContext = context.getApplicationContext();
        String key = cacheDir.getAbsolutePath() + "_" + config.hashCode();

        synchronized (CompleteACache.class) {
            Iterator<Map.Entry<String, WeakReference<CompleteACache>>> iterator = instanceMap.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, WeakReference<CompleteACache>> entry = iterator.next();
                if (entry.getValue().get() == null) {
                    iterator.remove();
                }
            }
            WeakReference<CompleteACache> ref = instanceMap.get(key);
            CompleteACache instance = ref != null ? ref.get() : null;

            if (instance == null) {
                instance = new CompleteACache(appContext, cacheDir, storageDir, config, key);
                instanceMap.put(key, new WeakReference<>(instance));
            }

            return instance;
        }
    }

    // ==================== 公开API ====================

    public void put(String key, String value) {
        put(key, value, -1);
    }

    public void put(String key, String value, int saveTime) {
        if (TextUtils.isEmpty(key) || value == null) return;

        Object data = config.compressLargeData && value.length() > COMPRESS_THRESHOLD ?
                compressString(value) : value;

        CacheItem item = new CacheItem(data, saveTime, "string");
        memoryCache.put(key, item);

        if (config.enablePersistence) {
            pendingWrites.add(key, item);
        }
    }

    public String getAsString(String key) {
        CacheItem item = getFromCache(key);
        if (item != null) {
            return unpackString(item.data);
        }

        if (config.enablePersistence) {
            Object data = diskCache.get(key, "string");
            if (data != null) {
                CacheItem diskItem = new CacheItem(data, -1, "string");
                memoryCache.put(key, diskItem);
                return unpackString(data);
            }
        }

        return null;
    }

    public void put(String key, JSONObject value) {
        put(key, value, -1);
    }

    public void put(String key, JSONObject value, int saveTime) {
        if (value == null) return;
        put(key, value.toString(), saveTime);
    }

    public JSONObject getAsJSONObject(String key) {
        String json = getAsString(key);
        if (json != null) {
            try {
                return new JSONObject(json);
            } catch (JSONException e) {
                Log.e(TAG, "Parse JSONObject error", e);
            }
        }
        return null;
    }

    public void put(String key, JSONArray value) {
        put(key, value, -1);
    }

    public void put(String key, JSONArray value, int saveTime) {
        if (value == null) return;
        put(key, value.toString(), saveTime);
    }

    public JSONArray getAsJSONArray(String key) {
        String json = getAsString(key);
        if (json != null) {
            try {
                return new JSONArray(json);
            } catch (JSONException e) {
                Log.e(TAG, "Parse JSONArray error", e);
            }
        }
        return null;
    }

    public void put(String key, byte[] value) {
        put(key, value, -1);
    }

    public void put(String key, byte[] value, int saveTime) {
        if (value == null) return;

        Object data = config.compressLargeData && value.length > COMPRESS_THRESHOLD ?
                compressData(value) : value;

        CacheItem item = new CacheItem(data, saveTime, "binary");
        memoryCache.put(key, item);

        if (config.enablePersistence) {
            pendingWrites.add(key, item);
        }
    }

    public byte[] getAsBinary(String key) {
        CacheItem item = getFromCache(key);
        if (item != null) {
            return unpackBinary(item.data);
        }

        if (config.enablePersistence) {
            Object data = diskCache.get(key, "binary");
            if (data != null) {
                CacheItem diskItem = new CacheItem(data, -1, "binary");
                memoryCache.put(key, diskItem);
                return unpackBinary(data);
            }
        }

        return null;
    }

    public void put(String key, Bitmap bitmap) {
        put(key, bitmap, -1);
    }

    public void put(String key, Bitmap bitmap, int saveTime) {
        if (bitmap == null) return;

        byte[] bytes = bitmapToBytes(bitmap);
        Object data = config.compressLargeData ? compressData(bytes) : bytes;

        CacheItem item = new CacheItem(data, saveTime, "bitmap");
        memoryCache.put(key, item);

        if (config.enablePersistence) {
            pendingWrites.add(key, item);
        }
    }

    public Bitmap getAsBitmap(String key) {
        byte[] bytes = getAsBinary(key);
        if (bytes != null) {
            return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
        }
        return null;
    }

    public void put(String key, Drawable drawable) {
        put(key, drawable, -1);
    }

    public void put(String key, Drawable drawable, int saveTime) {
        if (drawable == null) return;
        put(key, drawableToBitmap(drawable), saveTime);
    }

    public Drawable getAsDrawable(String key) {
        Bitmap bitmap = getAsBitmap(key);
        if (bitmap != null) {
            return new BitmapDrawable(appContext.getResources(), bitmap);
        }
        return null;
    }

    public void put(String key, Serializable value) {
        put(key, value, -1);
    }

    public void put(String key, Serializable value, int saveTime) {
        if (value == null) return;

        byte[] bytes = serializeObject(value);
        if (bytes == null) return;

        Object data = config.compressLargeData && bytes.length > COMPRESS_THRESHOLD ?
                compressData(bytes) : bytes;

        CacheItem item = new CacheItem(data, saveTime, "serializable");
        memoryCache.put(key, item);

        if (config.enablePersistence) {
            pendingWrites.add(key, item);
        }
    }

    // 添加 boolean 类型存储方法
    public void put(String key, boolean value) {
        put(key, String.valueOf(value), -1);
    }

    public void put(String key, boolean value, int saveTime) {
        put(key, String.valueOf(value), saveTime);
    }

    // 添加 boolean 类型读取方法
    public boolean getAsBoolean(String key) {
        return getAsBoolean(key, false); // 默认值为 false
    }

    public boolean getAsBoolean(String key, boolean defaultValue) {
        String value = getAsString(key);
        if (value != null) {
            if ("true".equalsIgnoreCase(value)) {
                return true;
            } else if ("false".equalsIgnoreCase(value)) {
                return false;
            }
        }
        return defaultValue;
    }


    public <T extends Serializable> T getAsObject(String key) {
        byte[] bytes = getAsBinary(key);
        if (bytes != null) {
            return deserializeObject(bytes);
        }
        return null;
    }

    public File getFile(String key) {
        if (config.enablePersistence) {
            return diskCache.getFile(key);
        }
        return null;
    }

    public boolean remove(String key) {
        memoryCache.remove(key);
        weakCache.remove(key);

        if (config.enablePersistence) {
            return diskCache.remove(key);
        }
        return true;
    }

    public void clearMemoryCache() {
        memoryCache.evictAll();
        weakCache.clear();
    }

    public void clear() {
        clearMemoryCache();

        if (config.enablePersistence) {
            ioExecutor.execute(diskCache::clear);
        }
    }

    public void flush() {
        pendingWrites.flushNow();
    }

    @Override
    public void close() {
        flush();
        clearMemoryCache();
        instanceMap.remove(instanceKey);
    }

    // ==================== 内部方法 ====================

    private CacheItem getFromCache(String key) {
        CacheItem item = memoryCache.get(key);
        if (item != null && !item.isDue()) {
            return item;
        }

        WeakReference<CacheItem> ref = weakCache.get(key);
        if (ref != null) {
            CacheItem weakItem = ref.get();
            if (weakItem != null && !weakItem.isDue()) {
                memoryCache.put(key, weakItem);
                return weakItem;
            }
        }

        return null;
    }

    private byte[] compressString(String str) {
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
             GZIPOutputStream gzip = new GZIPOutputStream(bos)) {
            gzip.write(str.getBytes(StandardCharsets.UTF_8));
            gzip.finish();
            return bos.toByteArray();
        } catch (IOException e) {
            Log.w(TAG, "String compression failed", e);
            return str.getBytes(StandardCharsets.UTF_8);
        }
    }

    private String unpackString(Object data) {
        if (data instanceof String) {
            return (String) data;
        } else if (data instanceof byte[]) {
            try (ByteArrayInputStream bis = new ByteArrayInputStream((byte[]) data);
                 GZIPInputStream gzip = new GZIPInputStream(bis);
                 ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
                byte[] buffer = new byte[1024];
                int len;
                while ((len = gzip.read(buffer)) > 0) {
                    bos.write(buffer, 0, len);
                }
                return bos.toString(StandardCharsets.UTF_8.name());
            } catch (IOException e) {
                Log.w(TAG, "String decompression failed", e);
                return new String((byte[]) data, StandardCharsets.UTF_8);
            }
        }
        return null;
    }

    private byte[] compressData(byte[] data) {
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
             DeflaterOutputStream dos = new DeflaterOutputStream(bos)) {
            dos.write(data);
            dos.finish();
            return bos.toByteArray();
        } catch (IOException e) {
            Log.w(TAG, "Data compression failed", e);
            return data;
        }
    }

    private byte[] unpackBinary(Object data) {
        if (data instanceof byte[]) {
            byte[] bytes = (byte[]) data;
            if (!isCompressed(bytes)) {
                return bytes;
            }

            try (ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
                 InflaterInputStream iis = new InflaterInputStream(bis);
                 ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
                byte[] buffer = new byte[1024];
                int len;
                while ((len = iis.read(buffer)) > 0) {
                    bos.write(buffer, 0, len);
                }
                return bos.toByteArray();
            } catch (IOException e) {
                Log.w(TAG, "Data decompression failed", e);
                return bytes;
            }
        }
        return null;
    }

    private boolean isCompressed(byte[] data) {
        if (data == null || data.length < 2) {
            return false;
        }
        return (data[0] == (byte) GZIPInputStream.GZIP_MAGIC)
                && (data[1] == (byte) (GZIPInputStream.GZIP_MAGIC >> 8));
    }

    private byte[] bitmapToBytes(Bitmap bitmap) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
        return baos.toByteArray();
    }

    private Bitmap drawableToBitmap(Drawable drawable) {
        if (drawable instanceof BitmapDrawable) {
            return ((BitmapDrawable) drawable).getBitmap();
        }

        int width = drawable.getIntrinsicWidth();
        int height = drawable.getIntrinsicHeight();
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);
        return bitmap;
    }

    private byte[] serializeObject(Serializable obj) {
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
             ObjectOutputStream oos = new ObjectOutputStream(bos)) {
            oos.writeObject(obj);
            return bos.toByteArray();
        } catch (IOException e) {
            Log.e(TAG, "Serialization failed", e);
            return null;
        }
    }

    @SuppressWarnings("unchecked")
    private <T extends Serializable> T deserializeObject(byte[] bytes) {
        try (ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
             ObjectInputStream ois = new ObjectInputStream(bis)) {
            return (T) ois.readObject();
        } catch (IOException | ClassNotFoundException e) {
            Log.e(TAG, "Deserialization failed", e);
            return null;
        }
    }

    private int calculateItemSize(CacheItem item) {
        if (item.data == null) return 0;

        if (item.data instanceof String) {
            return ((String) item.data).length() * 2;
        } else if (item.data instanceof byte[]) {
            return ((byte[]) item.data).length;
        } else if (item.data instanceof Bitmap) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                return ((Bitmap) item.data).getAllocationByteCount();
            }
            return ((Bitmap) item.data).getByteCount();
        }
        return 1024; // 默认1KB
    }

    private void scheduleWrite(String key, CacheItem item) {
        pendingWrites.add(key, item);
    }

    private void warmUpCache() {
        if (!config.enablePersistence) return;

        ioExecutor.execute(() -> {
            Map<String, Object> recentItems = diskCache.getRecentItems(20);
            for (Map.Entry<String, Object> entry : recentItems.entrySet()) {
                CacheItem item = new CacheItem(entry.getValue(), -1, "auto");
                item.dirty = false;
                memoryCache.put(entry.getKey(), item);
            }
        });
    }

    private void registerMemoryWatcher() {
        appContext.registerComponentCallbacks(new ComponentCallbacks2() {
            @Override
            public void onTrimMemory(int level) {
                if (level >= ComponentCallbacks2.TRIM_MEMORY_MODERATE) {
                    clearMemoryCache();
                }
            }

            @Override
            public void onConfigurationChanged(Configuration newConfig) {
            }

            @Override
            public void onLowMemory() {
                clearMemoryCache();
            }
        });
    }

    // ==================== 磁盘缓存实现 ====================

    private static final class DiskCacheManager {
        private static final String[] TYPES = {"string", "binary", "bitmap", "serializable"};

        private final File cacheDir;
        private final File storageDir;
        private final Config config;
        private final AtomicLong currentSize = new AtomicLong();
        private final Map<String, Long> lastAccessTimes = new ConcurrentHashMap<>();

        DiskCacheManager(File cacheDir, File storageDir, Config config) {
            this.cacheDir = cacheDir;
            this.storageDir = storageDir;
            this.config = config;
            initDirs();
            calculateSize();
        }

        private void initDirs() {
            if (!cacheDir.exists()) cacheDir.mkdirs();
            if (config.enablePersistence && !storageDir.exists()) storageDir.mkdirs();

            if (config.enablePersistence) {
                for (String type : TYPES) {
                    File dir = new File(storageDir, type);
                    if (!dir.exists()) dir.mkdirs();
                }
            }
        }

        synchronized void put(String key, Object value, String type) {
            if (!config.enablePersistence) return;

            File file = getFileForKey(key, type);
            try {
                if (value instanceof String) {
                    writeStringToFile(file, (String) value);
                } else if (value instanceof byte[]) {
                    writeBytesToFile(file, (byte[]) value);
                }

                lastAccessTimes.put(key, System.currentTimeMillis());
                currentSize.addAndGet(file.length());
                checkDiskUsage();
            } catch (IOException e) {
                Log.e(TAG, "Disk cache put failed", e);
            }
        }

        synchronized Object get(String key, String type) {
            File file = getFileForKey(key, type);
            if (!file.exists()) return null;

            lastAccessTimes.put(key, System.currentTimeMillis());

            try {
                if ("string".equals(type)) {
                    return readStringFromFile(file);
                } else {
                    return readBytesFromFile(file);
                }
            } catch (IOException e) {
                Log.e(TAG, "Disk cache get failed", e);
                return null;
            }
        }

        synchronized File getFile(String key) {
            for (String type : TYPES) {
                File file = getFileForKey(key, type);
                if (file.exists()) {
                    return file;
                }
            }
            return null;
        }

        synchronized Map<String, Object> getRecentItems(int count) {
            List<Map.Entry<String, Long>> entries = new ArrayList<>(lastAccessTimes.entrySet());
            // 修复API兼容性问题：使用Collections.sort替代List.sort
            Collections.sort(entries, new Comparator<Map.Entry<String, Long>>() {
                @Override
                public int compare(Map.Entry<String, Long> o1, Map.Entry<String, Long> o2) {
                    // 按访问时间倒序排列（最近访问的在前）
                    return o2.getValue().compareTo(o1.getValue());
                }
            });

            Map<String, Object> result = new HashMap<>();
            for (int i = 0; i < Math.min(count, entries.size()); i++) {
                String key = entries.get(i).getKey();
                for (String type : TYPES) {
                    Object value = get(key, type);
                    if (value != null) {
                        result.put(key, value);
                        break;
                    }
                }
            }
            return result;
        }

        synchronized boolean remove(String key) {
            boolean removed = false;
            for (String type : TYPES) {
                File file = getFileForKey(key, type);
                if (file.exists()) {
                    long length = file.length();
                    if (file.delete()) {
                        currentSize.addAndGet(-length);
                        lastAccessTimes.remove(key);
                        removed = true;
                    }
                }
            }
            return removed;
        }

        synchronized void clear() {
            for (String type : TYPES) {
                File dir = new File(storageDir, type);
                deleteDirectory(dir);
            }
            currentSize.set(0);
            lastAccessTimes.clear();
        }

        private File getFileForKey(String key, String type) {
            String filename = config.humanReadable ? key : Integer.toHexString(key.hashCode());
            return new File(new File(storageDir, type), filename);
        }

        private void writeStringToFile(File file, String content) throws IOException {
            try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
                writer.write(content);
            }
        }

        private String readStringFromFile(File file) throws IOException {
            StringBuilder sb = new StringBuilder((int) file.length());
            try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    sb.append(line);
                }
            }
            return sb.toString();
        }

        private void writeBytesToFile(File file, byte[] data) throws IOException {
            try (FileOutputStream fos = new FileOutputStream(file);
                 BufferedOutputStream bos = new BufferedOutputStream(fos)) {
                bos.write(data);
            }
        }

        private byte[] readBytesFromFile(File file) throws IOException {
            try (RandomAccessFile raf = new RandomAccessFile(file, "r")) {
                byte[] bytes = new byte[(int) raf.length()];
                raf.readFully(bytes);
                return bytes;
            }
        }

        private void deleteDirectory(File dir) {
            File[] files = dir.listFiles();
            if (files != null) {
                for (File file : files) {
                    if (file.isDirectory()) {
                        deleteDirectory(file);
                    } else {
                        long length = file.length();
                        if (file.delete()) {
                            currentSize.addAndGet(-length);
                        }
                    }
                }
            }
        }

        private void calculateSize() {
            long size = 0;
            for (String type : TYPES) {
                File dir = new File(storageDir, type);
                size += getFolderSize(dir);
            }
            currentSize.set(size);
        }

        private long getFolderSize(File dir) {
            long size = 0;
            File[] files = dir.listFiles();
            if (files != null) {
                for (File file : files) {
                    if (file.isFile()) {
                        size += file.length();
                        if (!lastAccessTimes.containsKey(file.getName())) {
                            lastAccessTimes.put(file.getName(), file.lastModified());
                        }
                    }
                }
            }
            return size;
        }

        private void checkDiskUsage() {
            if (currentSize.get() > config.maxDiskSize) {
                List<Map.Entry<String, Long>> entries = new ArrayList<>(lastAccessTimes.entrySet());
                // 修复API兼容性问题：使用Collections.sort替代List.sort
                // 修复API兼容性问题：手动实现比较器替代Map.Entry.comparingByValue()
                Collections.sort(entries, new Comparator<Map.Entry<String, Long>>() {
                    @Override
                    public int compare(Map.Entry<String, Long> o1, Map.Entry<String, Long> o2) {
                        // 按访问时间正序排列（最久未访问的在前）
                        return o1.getValue().compareTo(o2.getValue());
                    }
                });

                for (Map.Entry<String, Long> entry : entries) {
                    if (remove(entry.getKey())) {
                        if (currentSize.get() <= config.maxDiskSize * 0.9) {
                            break;
                        }
                    }
                }
            }
        }
    }

    // ==================== 延迟写入管理器 ====================

    private final class PendingWriteManager {
        private final Map<String, CacheItem> pendingItems = new ConcurrentHashMap<>();
        private volatile boolean writeScheduled = false;

        void add(String key, CacheItem item) {
            pendingItems.put(key, item);
            scheduleWrite();
        }

        void addAll(Map<String, CacheItem> items) {
            pendingItems.putAll(items);
            scheduleWrite();
        }

        private void scheduleWrite() {
            if (!writeScheduled && !pendingItems.isEmpty()) {
                writeScheduled = true;
                scheduledExecutor.schedule(this::flush, config.writeDelay, TimeUnit.MILLISECONDS);
            }
        }

        synchronized void flushNow() {
            if (pendingItems.isEmpty()) return;

            Map<String, CacheItem> itemsToWrite = new HashMap<>(pendingItems);
            pendingItems.clear();
            writeScheduled = false;

            ioExecutor.execute(() -> {
                for (Map.Entry<String, CacheItem> entry : itemsToWrite.entrySet()) {
                    if (entry.getValue().dirty) {
                        diskCache.put(entry.getKey(), entry.getValue().data, entry.getValue().type);
                        entry.getValue().dirty = false;
                    }
                }
            });
        }

        private void flush() {
            writeScheduled = false;
            flushNow();
        }
    }
}
